#include <iostream>
#include <typeinfo>
#include <assert.h>

class Any
{
private:
    class holder
    {
    public:
        virtual ~holder()
        {}
        // 数据类型
        virtual const std::type_info& type() = 0;
        // 克隆出新的对象
        virtual holder* clone() = 0;
    };
    template<class T>
    class placeholder: public holder
    {
    public:
        placeholder(const T& val): _val(val){}
        // 获取子类对象保存的数据类型
        virtual const std::type_info& type()
        {
            return typeid(T);
        }
        // 针对出当前的对象自身，克隆出一个新的对象
        virtual holder* clone()
        {
            return new placeholder(_val);
        }
    public:
        T _val;
    };
    holder* _content;
    public:
        Any():_content(NULL){}
        template<class T>
        Any(const T& val):_content(new placeholder<T>(val)){}
        Any(const Any& other):_content(other._content ? other._content->clone() : NULL) {}
        ~Any(){ delete _content;}

        Any &swap(Any& other)
        {
            std::swap(_content, other._content);
            return *this;
        }   

        template<class T>
        //返回子类对象保存的数据的指针
        T* get() 
        {
            // 想要获取的数据类型，必须和保存的数据类型一致
            //if(typeid(T) != _content->type()) return NULL;
            assert(typeid(T) == _content->type());
            return &((placeholder<T>*)_content)->_val;
        }
        //赋值运算符重载函数
        template<class T>
        Any& operator=(const T& val)
        {
            //为val构造一个临时的通用容器，然后与当前容器自身进行指针交换
            //临时对象释放的时候，原先保存的数据也就被释放了
            Any(val).swap(*this);
            return *this;
        }
        Any& operator=(const Any& other)
        {
            Any(other).swap(*this);
            return *this;
        }
};

class Test
{
public:
    Test() {std::cout << "构造" << std::endl;}
    Test() {std::cout << "析构" << std::endl;}
};

int main()
{
    Any a;

    {
        Test t;
        a = t;
    }
    
    a = 10;
    int* pa = a.get<int>();
    std::cout << *pa << std::endl;
    a = std::string("nihao");
    std::string *ps = a.get<std::string>();
    std::cout << *ps << std::endl;
    return 0;
}